package com.zbkj.crmeb.merchant.api.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.CommonPage;
import com.common.PageParamRequest;
import com.constants.Constants;
import com.crmeb.core.exception.CrmebException;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.utils.CrmebUtil;
import com.utils.DateUtil;
import com.utils.vo.AuthorizePhoneVo;
import com.zbkj.crmeb.chant.model.ChannelMerchantDistribution;
import com.zbkj.crmeb.chant.service.ChannelMerchantDistributionService;
import com.zbkj.crmeb.enums.CommissionTypeEnum;
import com.zbkj.crmeb.finance.model.UserRecharge;
import com.zbkj.crmeb.finance.request.FundsMonitorSearchRequest;
import com.zbkj.crmeb.finance.request.UserExtractRequest;
import com.zbkj.crmeb.finance.service.UserExtractService;
import com.zbkj.crmeb.finance.service.UserRechargeService;
import com.zbkj.crmeb.front.request.UserRechargeRequest;
import com.zbkj.crmeb.front.request.UserSpreadPeopleRequest;
import com.zbkj.crmeb.front.response.*;
import com.zbkj.crmeb.marketing.model.StoreCouponUser;
import com.zbkj.crmeb.marketing.service.StoreCouponUserService;
import com.zbkj.crmeb.merchant.api.service.MerUserCenterService;
import com.zbkj.crmeb.payment.service.RechargePayService;
import com.zbkj.crmeb.payment.vo.wechat.CreateOrderResponseVo;
import com.zbkj.crmeb.store.model.StoreOrder;
import com.zbkj.crmeb.store.model.StoreOrderInfo;
import com.zbkj.crmeb.store.model.UserCommission;
import com.zbkj.crmeb.store.service.StoreOrderInfoService;
import com.zbkj.crmeb.store.service.StoreOrderService;
import com.zbkj.crmeb.store.service.UserCommissionService;
import com.zbkj.crmeb.system.model.SystemUserLevel;
import com.zbkj.crmeb.system.request.SystemUserLevelSearchRequest;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.system.service.SystemGroupDataService;
import com.zbkj.crmeb.system.service.SystemUserLevelService;
import com.zbkj.crmeb.system.vo.SystemGroupDataRechargeConfigVo;
import com.zbkj.crmeb.user.dao.UserDao;
import com.zbkj.crmeb.user.model.User;
import com.zbkj.crmeb.user.model.UserBill;
import com.zbkj.crmeb.user.model.UserToken;
import com.zbkj.crmeb.user.request.AuthorizePhoneRequest;
import com.zbkj.crmeb.user.request.RegisterThirdUserRequest;
import com.zbkj.crmeb.user.request.UserOperateFundsRequest;
import com.zbkj.crmeb.user.service.UserBillService;
import com.zbkj.crmeb.user.service.UserService;
import com.zbkj.crmeb.user.service.UserTokenService;
import com.zbkj.crmeb.wechat.response.WeChatAuthorizeLoginGetOpenIdResponse;
import com.zbkj.crmeb.wechat.response.WeChatAuthorizeLoginUserInfoResponse;
import com.zbkj.crmeb.wechat.response.WeChatProgramAuthorizeLoginGetOpenIdResponse;
import com.zbkj.crmeb.wechat.service.WeChatService;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 用户中心 服务实现类
 * </p>
 *
 * @author Mr.Zhang
 * @since 2020-04-10
 */
@Service
public class MerUserCenterServiceImpl extends ServiceImpl<UserDao, User> implements MerUserCenterService {

    @Autowired
    private UserService userService;

    @Autowired
    private UserBillService userBillService;

    @Autowired
    private UserExtractService userExtractService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private SystemUserLevelService systemUserLevelService;

    @Autowired
    private SystemGroupDataService systemGroupDataService;

    @Autowired
    private StoreOrderService storeOrderService;

    @Autowired
    private UserRechargeService userRechargeService;

    @Autowired
    private RechargePayService rechargePayService;

    @Autowired
    private UserTokenService userTokenService;

    @Autowired
    private WeChatService weChatService;
    @Autowired
    private UserCommissionService userCommissionService;
    @Autowired
    private StoreOrderInfoService storeOrderInfoService;
    @Autowired
    private ChannelMerchantDistributionService channelMerchantDistributionService;
    @Autowired
    private StoreCouponUserService storeCouponUserService;

    /**
     * 推广数据接口(当前佣金 冻结佣金 可提佣金)
     * @author Mr.Zhang
     * @since 2020-06-08
     */
    @Override
    public UserCommissionResponse getCommission() {
        UserCommissionResponse userCommissionResponse = new UserCommissionResponse();
        User user = userService.getById(userService.getUserIdException());
        userCommissionResponse.setCommissionTotal(user.getBrokeragePrice());
        userCommissionResponse.setFreezeAmount(user.getFrozenPrice());
        userCommissionResponse.setCashAmount(user.getWithdrawalPrice());
        userCommissionResponse.setCloseAmount(user.getClosePrice());
        //冻结佣金
        //BigDecimal freezeAmount = userBillService.getSumBigDecimal(1, userService.getUserIdException(), Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE, null, Constants.USER_BILL_TYPE_PAY_PRODUCT);
        //userCommissionResponse.setFreezeAmount(freezeAmount);
        //可提佣金
        //BigDecimal cashAmount = userBillService.getSumBigDecimal(1, userService.getUserIdException(), Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE, null, Constants.USER_BILL_TYPE_BROKERAGE);
        //userCommissionResponse.setCashAmount(cashAmount);

//        //冻结佣金
//        BigDecimal freezeAmount = userCommissionService.selectFreezeAmount(userService.getUserIdException(), CommissionStatusEnum.YJDJ_佣金冻结.getCode());
//        userCommissionResponse.setFreezeAmount(freezeAmount);
//        //解冻金额
//        BigDecimal cashAmount =userCommissionService.selectFreezeAmount(userService.getUserIdException(), CommissionStatusEnum.YJJD_佣金解冻.getCode());
//        userCommissionResponse.setCashAmount(cashAmount);
//                //当前佣金
//        userCommissionResponse.setCommissionTotal(freezeAmount.add(cashAmount));

        return userCommissionResponse;
    }

    /**
     * 推广佣金明细
     * @author Mr.Zhang
     * @since 2020-06-08
     * @return UserSpreadCommissionResponse
     */
    @Override
    public PageInfo<UserSpreadCommissionResponse> getSpreadCommissionByType(int type, PageParamRequest pageParamRequest) {
        Integer pm = null;
        List<String> categoryList = new ArrayList<>();
        //佣金类型|0=全部,1=支出,2=收入,3=佣金明细,4=提现明细
        switch (type){
            case 0:
                categoryList.add(Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE);
                categoryList.add(Constants.USER_BILL_CATEGORY_MONEY);
                break;
            case 1:
                //pm:0 支出：购买商品 (brokerage_price)
                pm = 0;
                categoryList.add(Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE);
                break;
            case 2:
                //pm:1 收入：后台操作、商品退款
                pm = 1;
                categoryList.add(Constants.USER_BILL_CATEGORY_MONEY);
                break;
            case 3:
                categoryList.add(Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE);
                break;
            case 4:
                return null;
            default:
                break;
        }

        return userBillService.getListGroupByMonth(userService.getUserIdException(), pm, pageParamRequest, categoryList);
    }

    /**
     * 推广佣金/提现总和
     * @author Mr.Zhang
     * @since 2020-06-08
     * @return BigDecimal
     */
    @Override
    public BigDecimal getSpreadCountByType(int type) {
        //推广佣金/提现总和
        Integer userId = userService.getUserIdException();
        if(type == 3){
            BigDecimal count = userBillService.getSumBigDecimal(null, userId, Constants.USER_BILL_CATEGORY_MONEY, null, Constants.USER_BILL_TYPE_BROKERAGE);
            BigDecimal withdraw = userBillService.getSumBigDecimal(1, userId, Constants.USER_BILL_CATEGORY_MONEY, null, Constants.USER_BILL_TYPE_BROKERAGE); //提现
            return count.subtract(withdraw);
        }

        //累计提现
        if(type == 4){
            return userExtractService.getWithdrawn(userId);
        }

        return BigDecimal.ZERO;
    }

    /**
     * 提现申请
     * @author Mr.Zhang
     * @since 2020-06-08
     * @return Boolean
     */
    @Override
    public Boolean extractCash(UserExtractRequest request) {
        return userExtractService.create(request, userService.getUserIdException());
    }

    /**
     * 提现银行/提现最低金额
     * @author Mr.Zhang
     * @since 2020-06-08
     * @return UserExtractCashResponse
     */
    @Override
    public UserExtractCashResponse minExtractCash() {
        String bank = systemConfigService.getValueByKeyException(Constants.CONFIG_BANK_LIST).replace("\r\n", "\n");
        /*String minPrice = systemConfigService.getValueByKeyException(Constants.CONFIG_EXTRACT_MIN_PRICE);*/

        String extractTime = systemConfigService.getValueByKey(Constants.CONFIG_EXTRACT_FREEZING_TIME);


        /*BigDecimal brokeragePrice = userService.getInfo().getWithdrawalPrice();
        BigDecimal freeze = userExtractService.getFreeze(userService.getUserIdException());*/
        String minPrice = BigDecimal.ZERO.toString();
        User user = userService.getInfo();
        if (Objects.nonNull(user)){
            ChannelMerchantDistribution distribution = channelMerchantDistributionService.getOne(Wrappers.<ChannelMerchantDistribution>lambdaQuery().eq(ChannelMerchantDistribution::getMerId, user.getMerId()));
            if(Objects.isNull(distribution)) {
                throw new CrmebException("当前分销模式未启用!");
            }
            minPrice = distribution.getMinPrice().toString();
        }
        BigDecimal brokeragePrice = Objects.isNull(user) ? BigDecimal.ZERO : user.getWithdrawalPrice();
        BigDecimal freeze = Objects.isNull(user) ? BigDecimal.ZERO : user.getFrozenPrice();

        return new UserExtractCashResponse(
                CrmebUtil.stringToArrayStr(bank),
                minPrice,
                brokeragePrice.subtract(freeze),
                freeze,
                extractTime
        );
    }

    /**
     * 会员等级列表
     * @author Mr.Zhang
     * @since 2020-06-19
     * @return List<UserLevel>
     */
    @Override
    public List<SystemUserLevel> getUserLevelList() {
        SystemUserLevelSearchRequest request = new SystemUserLevelSearchRequest();
        request.setIsShow(true);
        request.setIsDel(false);
        return systemUserLevelService.getList(request, new PageParamRequest());
    }

    /**
     * 推广用户， 我自己推广了哪些用户
     * @author Mr.Zhang
     * @since 2020-05-18
     * @return UserSpreadPeopleResponse
     */
    @Override
    public UserSpreadPeopleResponse getSpreadPeopleList(UserSpreadPeopleRequest request, PageParamRequest pageParamRequest) {

        List<Integer> userIdList = new ArrayList<>();
        UserSpreadPeopleResponse userSpreadPeopleResponse = new UserSpreadPeopleResponse();

        //一级推广
        List<Integer> firstUserIdList = userService.getSpreadPeopleIdListByUserId(userService.getUserIdException());
        userSpreadPeopleResponse.setFirstTotal(firstUserIdList.size());

        //二级推广
        List<Integer> secondUserIdList = new ArrayList<>();
        for (Integer userId: firstUserIdList){
            secondUserIdList.addAll(userService.getSpreadPeopleIdListByUserId(userId));
        }
        userSpreadPeopleResponse.setSecondTotal(secondUserIdList.size());

        //一级推广
        if(request.getGrade() == 0){
            userIdList.addAll(firstUserIdList);
        }

        //二级推广
        if(request.getGrade() == 1){
            userIdList.addAll(secondUserIdList);
        }

        //推广人列表
        if(userIdList.size() > 0){
            List<UserSpreadPeopleItemResponse> userSpreadPeopleItemResponseList = userService.getSpreadPeopleList(userIdList, request.getKeyword(), request.getSortKey(), request.getIsAsc(), pageParamRequest);
            userSpreadPeopleResponse.setSpreadPeopleList(userSpreadPeopleItemResponseList);
        }

        return userSpreadPeopleResponse;
    }

    /**
     * 积分记录
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return List<UserBill>
     */
    @Override
    public List<UserBill> getUserBillList(String category, PageParamRequest pageParamRequest) {
        FundsMonitorSearchRequest request = new FundsMonitorSearchRequest();
        request.setUid(userService.getUserIdException());
        request.setCategory(category);
        return userBillService.getList(request, pageParamRequest);
    }

    /**
     * 充值额度选择
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserRechargeResponse
     */
    @Override
    public UserRechargeResponse getRechargeConfig() {
        UserRechargeResponse userRechargeResponse = new UserRechargeResponse();
        userRechargeResponse.setRechargeQuota(systemGroupDataService.getListByGid(Constants.GROUP_DATA_ID_RECHARGE_LIST, UserRechargeItemResponse.class));
        String rechargeAttention = systemConfigService.getValueByKey(Constants.CONFIG_RECHARGE_ATTENTION);
        List<String> rechargeAttentionList = new ArrayList<>();
        if(StringUtils.isNotBlank(rechargeAttention)){
            rechargeAttentionList = CrmebUtil.stringToArrayStrRegex(rechargeAttention, "\n");
        }
        userRechargeResponse.setRechargeAttention(rechargeAttentionList);
        return userRechargeResponse;
    }

    /**
     * 用户资金统计
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserBalanceResponse
     */
    @Override
    public UserBalanceResponse getUserBalance() {
        User info = userService.getInfo();
        BigDecimal recharge = userBillService.getSumBigDecimal(1, info.getUid(), Constants.USER_BILL_CATEGORY_MONEY, null, null);
        BigDecimal orderStatusSum = storeOrderService.getSumBigDecimal(info.getUid(), null);
        return new UserBalanceResponse(info.getNowMoney(), recharge, orderStatusSum);
    }

    /**
     * 推广订单
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserSpreadOrderResponse;
     */
    @Override
    public UserSpreadOrderResponse getSpreadOrder(PageParamRequest pageParamRequest) {
        UserSpreadOrderResponse userSpreadOrderResponse = new UserSpreadOrderResponse();

        List<Integer> userIdList = new ArrayList<>();

        //登录的用户A
        Integer uId = userService.getUserIdException();
        if (null != uId) {
            userIdList.add(uId);
        }

        if(CollectionUtil.isEmpty(userIdList)){
            return userSpreadOrderResponse;
        }

        //查询所有推广人的由于订单获取佣金记录，分页
        FundsMonitorSearchRequest request = new FundsMonitorSearchRequest();
        ArrayList<String> categoryList = new ArrayList<>();
        request.setCategory(Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE);
        request.setUserIdList(userIdList);
        List<UserBill> list = userBillService.getList(request, pageParamRequest);
        if(null == list){
            return userSpreadOrderResponse;
        }
        CommonPage<UserBill> userBillCommonPage = CommonPage.restPage(list); //拿到分页信息
        userSpreadOrderResponse.setCount(userBillCommonPage.getTotal()); //总数

        //拿到订单id, 查询订单信息
        List<Integer> orderIdList = list.stream().map(i -> Integer.parseInt(i.getLinkId())).distinct().collect(Collectors.toList());
        Map<Integer, StoreOrder> orderList = storeOrderService.getMapInId(orderIdList);

        //用户信息
        userIdList = list.stream().map(UserBill::getUid).distinct().collect(Collectors.toList());
        HashMap<Integer, User> userList = userService.getMapListInUid(userIdList);

        //按时间分组数据
        List<UserSpreadOrderItemResponse> userSpreadOrderItemResponseList = new ArrayList<>();
        for (UserBill userBill : list) {
            String date = DateUtil.dateToStr(userBill.getCreateTime(), Constants.DATE_FORMAT_MONTH);
            boolean isAdd = false;
            String orderId = "";
            Date createTime = null;
            String avatar = "";
            String nickname = "";
            Integer linkId = Integer.parseInt(userBill.getLinkId());
            if(null != orderList && orderList.containsKey(linkId)){
                orderId = orderList.get(linkId).getOrderId();
                createTime = orderList.get(linkId).getCreateTime();
                Integer uid = orderList.get(linkId).getUid();
                //下单人
                if (null != uid) {
                    User orderUser = userService.getById(uid);
                    if (ObjectUtil.isNotEmpty(orderUser)) {
                        avatar = orderUser.getAvatar();
                        nickname = orderUser.getNickname();
                    }
                }
            }

            UserSpreadOrderItemChildResponse userSpreadOrderItemChildResponse = new UserSpreadOrderItemChildResponse(
                    orderId, //订单号
                    createTime, //订单创建时间
                    (userBill.getStatus() == 1) ? userBill.getNumber() : BigDecimal.ZERO,
                    avatar,
                    nickname,
                    userBill.getType()
            );

            //如果在已有的数据中找到当前月份数据则追加
            for (UserSpreadOrderItemResponse userSpreadOrderItemResponse: userSpreadOrderItemResponseList) {
                if(userSpreadOrderItemResponse.getTime().equals(date)){
                    userSpreadOrderItemResponse.getChild().add(userSpreadOrderItemChildResponse);
                    isAdd = true;
                    break;
                }
            }

            //没月找到则创建一条数据
            if(!isAdd){
                //创建一个
                UserSpreadOrderItemResponse userSpreadOrderItemResponse = new UserSpreadOrderItemResponse();
                userSpreadOrderItemResponse.setTime(date);
                userSpreadOrderItemResponse.getChild().add(userSpreadOrderItemChildResponse);
                userSpreadOrderItemResponseList.add(userSpreadOrderItemResponse);
            }
        }

        List<String> monthList = userSpreadOrderItemResponseList.stream().map(s -> "'" + s.getTime() + "'").collect(Collectors.toList());

        if(monthList.size() < 1){
            return userSpreadOrderResponse;
        }

        //获取每个月分的总数
        Map<String, Integer> countMap = userBillService.getCountListByMonth(request, monthList);

        //统计每月的订单数量
        for (UserSpreadOrderItemResponse userSpreadOrderItemResponse: userSpreadOrderItemResponseList) {
            userSpreadOrderItemResponse.setCount(countMap.get(userSpreadOrderItemResponse.getTime()));
        }

        userSpreadOrderResponse.setList(userSpreadOrderItemResponseList);

        return userSpreadOrderResponse;
    }

    /**
     * 充值
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserSpreadOrderResponse;
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, CrmebException.class})
    public UserRechargePaymentResponse recharge(UserRechargeRequest request) {
        request.setPayType(Constants.PAY_TYPE_WE_CHAT);

        //验证金额是否为最低金额
        String rechargeMinAmountStr = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_RECHARGE_MIN_AMOUNT);
        BigDecimal rechargeMinAmount = new BigDecimal(rechargeMinAmountStr);
        int compareResult = rechargeMinAmount.compareTo(request.getPrice());
        if(compareResult > 0){
            throw new CrmebException("充值金额不能低于" + rechargeMinAmountStr);
        }
        request.setPrice(request.getPrice());
        request.setGivePrice(BigDecimal.ZERO);

        if(request.getGroupDataId() > 0){
            SystemGroupDataRechargeConfigVo systemGroupData = systemGroupDataService.getNormalInfo(request.getGroupDataId(), SystemGroupDataRechargeConfigVo.class);
            if(null == systemGroupData){
                throw new CrmebException("您选择的充值方式已下架");
            }

            //售价和赠送
            request.setPrice(systemGroupData.getPrice());
            request.setGivePrice(BigDecimal.ZERO);

        }
        //生成系统订单
        request.setUserId(userService.getUserIdException());

        UserRecharge userRecharge = userRechargeService.create(request);

        //微信支付
        try{
            CreateOrderResponseVo responseVo = rechargePayService.payOrder(userRecharge.getId(), request.getPayType(), request.getClientIp());
            if(null == responseVo){
                throw new CrmebException("下单失败！");
            }
            responseVo.setMerId(userRecharge.getMerId());
            return weChatService.response(responseVo);
        }catch (Exception e){
            throw new CrmebException(e.getMessage());
        }
    }

    /**
     * 微信登录
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserSpreadOrderResponse;
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, CrmebException.class})
    public LoginResponse weChatAuthorizeLogin(String code, Integer spreadUid, Integer merId) {
        try{
            WeChatAuthorizeLoginGetOpenIdResponse response = weChatService.authorizeLogin(code);
            User user = publicLogin(response.getOpenId(), response.getAccessToken(), merId);
            //通过用户id获取登录token信息
            LoginResponse loginResponse = new LoginResponse();
            loginResponse.setToken(userService.token(user));
            user.setPwd(null);
            //绑定推广关系
            userService.bindSpread(user, spreadUid);
            loginResponse.setUser(user);

            return loginResponse;
        }catch (Exception e){
            throw new CrmebException(e.getMessage());
        }
    }

    /**
     * 通过openId登录
     * @param openId  String 微信公众号通过code取回的openId对象
     * @param token String code换取的token
     * @author Mr.Zhang
     * @since 2020-05-25
     * @return List<LoginResponse>
     */
    private User publicLogin(String openId, String token, Integer merId) {
        try {
            //检测是否存在
            UserToken userToken = userTokenService.checkToken(openId,  Constants.THIRD_LOGIN_TOKEN_TYPE_PUBLIC);
            if(null != userToken){
                return userService.getById(userToken.getUid());
            }

            //没有注册， 获取微信用户信息， 小程序需要前端传入用户信息参数
            WeChatAuthorizeLoginUserInfoResponse userInfo = weChatService.getUserInfo(openId, token);
            RegisterThirdUserRequest registerThirdUserRequest = new RegisterThirdUserRequest();
            BeanUtils.copyProperties(userInfo, registerThirdUserRequest);
            String unionId = userInfo.getUnionId();

            //看unionid是否已经绑定
            if(StringUtils.isNotBlank(unionId)){
                userToken = userTokenService.checkToken(userInfo.getUnionId(), Constants.THIRD_LOGIN_TOKEN_TYPE_UNION_ID);
                if(null != userToken){
                    return userService.getById(userToken.getUid());
                }
            }

            //TODO 是否需要强制注册用户，1 强制注册，2 需要返回数据给前端，让其输入手机号和验证码
            registerThirdUserRequest.setMerId(merId);
            User user = userService.registerByThird(registerThirdUserRequest, Constants.USER_LOGIN_TYPE_PUBLIC);

            userTokenService.bind(openId, Constants.THIRD_LOGIN_TOKEN_TYPE_PUBLIC, user.getUid());
            if(StringUtils.isNotBlank(unionId)) {
                //有就绑定
                userTokenService.bind(unionId, Constants.THIRD_LOGIN_TOKEN_TYPE_UNION_ID, user.getUid());
            }
            return user;
        }catch (Exception e){
            throw new CrmebException(e.getMessage());
        }
    }

    /**
     * 获取微信授权logo
     * @author Mr.Zhang
     * @since 2020-06-29
     * @return String;
     */
    @Override
    public String getLogo() {
        String url = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PROGRAM_LOGO);
        if(StringUtils.isNotBlank(url) && !url.contains("http")){
            url = systemConfigService.getValueByKey(Constants.CONFIG_KEY_SITE_URL) + url;
            url = url.replace("\\", "/");
        }
        return url;
    }

    /**
     * 小程序登录
     * @param code String 前端临时授权code
     * @param request RegisterThirdUserRequest 用户信息
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return UserSpreadOrderResponse;
     */
    @Override
    public LoginResponse weChatAuthorizeProgramLogin(String code, RegisterThirdUserRequest request) {
        try{
            WeChatProgramAuthorizeLoginGetOpenIdResponse response = weChatService.programAuthorizeLogin(code, request);
            User user = programLogin(response.getOpenId(), response.getUnionId(), request);
            //通过用户id获取登录token信息
            LoginResponse loginResponse = new LoginResponse();
            loginResponse.setToken(userService.token(user));
            loginResponse.setSessionKey(response.getSessionKey());
            user.setPwd(null);
            //绑定推广关系
            userService.bindSpread(user, request.getSpreadPid());
            loginResponse.setUser(user);

            return loginResponse;
        }catch (Exception e){
            e.printStackTrace();
        }
        
        return null;
    }

    /**
     * 推广人排行榜
     * @param type  String 时间范围
     * @param pageParamRequest PageParamRequest 分页
     * @author Mr.Zhang
     * @since 2020-05-25
     * @return List<LoginResponse>
     */
    @Override
    public List<User> getTopSpreadPeopleListByDate(String type, PageParamRequest pageParamRequest) {
        return userService.getTopSpreadPeopleListByDate(type, pageParamRequest);
    }

    /**
     * 佣金排行榜
     * @param type  String 时间范围
     * @param pageParamRequest PageParamRequest 分页
     * @author Mr.Zhang
     * @since 2020-05-25
     * @return List<LoginResponse>
     */
    @Override
    public List<User> getTopBrokerageListByDate(String type, PageParamRequest pageParamRequest) {
        List<UserBill> userBillVoList = userBillService.getTopBrokerageListByDate(type, pageParamRequest);
        if(userBillVoList.size() < 1){
            return null;
        }

        List<Integer> uidList = userBillVoList.stream().map(UserBill::getUid).collect(Collectors.toList());
        if(uidList.size() < 1){
            return null;
        }

        ArrayList<User> userList = new ArrayList<>();
        //查询用户
        HashMap<Integer, User> userVoList = userService.getMapListInUid(uidList);

        //解决排序问题
        for (UserBill userBillVo: userBillVoList) {
            User user = new User();
            User userVo = userVoList.get(userBillVo.getUid());

            user.setUid(userBillVo.getUid());
            user.setAvatar(userVo.getAvatar());
            user.setBrokeragePrice(userBillVo.getNumber());
            if(StringUtils.isBlank(userVo.getNickname())){
                user.setNickname(userVo.getPhone().substring(0, 2) + "****" + userVo.getPhone().substring(7));
            }else{
                user.setNickname(userVo.getNickname());
            }

            userList.add(user);
        }

        return userList;
    }

    /**
     * 推广海报图
     * @author Mr.Zhang
     * @since 2020-06-10
     * @return List<SystemGroupData>
     */
    @Override
    public List<UserSpreadBannerResponse> getSpreadBannerList(PageParamRequest pageParamRequest,Integer merId) {
        return systemGroupDataService.getListByGid(Constants.GROUP_DATA_ID_SPREAD_BANNER_LIST, UserSpreadBannerResponse.class,merId);
    }

    /**
     * 当前用户在佣金排行第几名
     * @param type  String 时间范围
     * @return 优惠券集合
     */
    @Override
    public Integer getNumberByTop(String type) {
        int number = 0;
        Integer userId = userService.getUserIdException();
        PageParamRequest pageParamRequest = new PageParamRequest();
        pageParamRequest.setLimit(100);

        List<UserBill> userBillVoList = userBillService.getTopBrokerageListByDate(type, pageParamRequest);
        if(userBillVoList.size() < 1){
            return number;
        }

        List<Integer> uidList = userBillVoList.stream().map(UserBill::getUid).collect(Collectors.toList());
        if(uidList.size() < 1){
            return number;
        }

        int i = 1;
        for (UserBill userBill : userBillVoList) {
            if(userBill.getUid().equals(userId)){
                number = i;
                break;
            }
            i++;
        }

        return number;
    }

    /**
     * 佣金转入余额
     * @author Mr.Zhang
     * @since 2020-05-18
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, CrmebException.class})
    public Boolean transferIn(BigDecimal price) {
        try{
            //当前可提现佣金
            User user = userService.getInfo();
            BigDecimal freeze = userExtractService.getFreeze(user.getUid()); //冻结佣金
            BigDecimal subtract = user.getBrokeragePrice().subtract(freeze);

            if(subtract.compareTo(price) < 0){
                throw new CrmebException("您当前可充值余额为 " + subtract + "元");
            }

            UserOperateFundsRequest request = new UserOperateFundsRequest();
            request.setFoundsCategory(Constants.USER_BILL_CATEGORY_BROKERAGE_PRICE);
            request.setType(0);
            request.setFoundsType(Constants.USER_BILL_TYPE_TRANSFER_IN);
            request.setUid(user.getUid());
            request.setValue(price);
            request.setTitle("佣金转余额");
            userService.updateFounds(request, true); //更新佣金


            UserOperateFundsRequest money = new UserOperateFundsRequest();
            money.setFoundsCategory(Constants.USER_BILL_CATEGORY_MONEY);
            money.setType(1);
            money.setFoundsType(Constants.USER_BILL_TYPE_TRANSFER_IN);
            money.setUid(user.getUid());
            money.setValue(price);
            money.setTitle("佣金转余额");
            userService.updateFounds(money, true); //更新佣金
            return true;
        }catch (Exception e){
            throw new CrmebException("操作失败：" + e.getMessage());
        }

    }

    /**
     * 小程序登录
     * @param openId  String 微信公众号通过code取回的openId对象
     * @param unionId String unionId
     * @author Mr.Zhang
     * @since 2020-05-25
     * @return List<LoginResponse>
     */
    private User programLogin(String openId, String unionId, RegisterThirdUserRequest request) {
        try {
            //检测是否存在
            UserToken userToken = userTokenService.checkToken(openId, Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM);
            if(null != userToken){
                return userService.getById(userToken.getUid());
            }

            if(StringUtils.isNotBlank(unionId)) {
                userToken = userTokenService.checkToken(unionId, Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM);
                if (null != userToken) {
                    return userService.getById(userToken.getUid());
                }
            }

            //TODO 是否需要强制注册用户，1 强制注册，2 需要返回数据给前端，让其输入手机号和验证码
            User user = userService.registerByThird(request, Constants.USER_LOGIN_TYPE_PROGRAM);

            userTokenService.bind(openId, Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM, user.getUid());
            if(StringUtils.isNotBlank(unionId)) {
                //有就绑定
                userTokenService.bind(unionId, Constants.THIRD_LOGIN_TOKEN_TYPE_UNION_ID, user.getUid());
            }
            return user;
        }catch (Exception e){
            throw new CrmebException(e.getMessage());
        }
    }
    
    /**
     * 微信登录小程序 - 授权获取用户手机号
     *
     * @param request
     * @return
     */
    @Override
    public Boolean getAuthorizePhone(AuthorizePhoneRequest request) {

        //解密用户手机号
        String result = decryptUserPhone(request);

        if (StringUtils.isNotBlank(result)) {
            //解析数据
            AuthorizePhoneVo authorizePhone = dealAuthorizePhoneResult(result);
            if (ObjectUtil.isNotEmpty(authorizePhone)) {
                //授权手机号为空
                String phoneNumber = authorizePhone.getPhoneNumber();
                if (StringUtils.isBlank(phoneNumber)) {
                    return false;
                }
                //加国家区域号
                if (StringUtils.isNotBlank(authorizePhone.getCountryCode())) {
                    phoneNumber = "+" + authorizePhone.getCountryCode() + " " + phoneNumber;
                }
                //保存用户手机号
                LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper();
                updateWrapper.eq(User::getUid, request.getUid());
                updateWrapper.set(User::getPhone, phoneNumber);
                updateWrapper.set(User::getUpdateTime, DateUtil.nowDateTime());
                return userService.update(updateWrapper);
            }
        }

        return false;
    }

    @Override
    public CommonPage<StoreOrder> getV2SpreadOrder(PageParamRequest pageParamRequest) {
        Integer userId = userService.getUserIdException();
        List<Integer> userIdList = userService.getChildUidList(userId);
        if(null!=userIdList && userIdList.size() > 0){
            StoreOrder order = new StoreOrder();
            order.setUidList(userIdList);
            List<StoreOrder> list = storeOrderService.getUserOrderList(order,pageParamRequest);
            list.stream().forEach(storeOrder ->{
                User user = userService.getById(storeOrder.getUid());
                if(null!=user){
                    storeOrder.setMark(user.getAvatar());
                }
            });
            return CommonPage.restPage(list);
        }
        return CommonPage.restPage(new ArrayList<>());
    }

    @Override
    public List<UserBill> getIntegralList(Integer type, PageParamRequest pageParamRequest) {
        Integer uid = userService.getUserIdException();
        PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        List<UserBill> userBillList = userBillService.list(Wrappers.<UserBill>lambdaQuery().eq(UserBill::getCategory,Constants.USER_BILL_CATEGORY_INTEGRAL).eq(type != null, UserBill::getPm, type).eq(UserBill::getUid, uid).orderByDesc(UserBill::getId));
        if(CollectionUtils.isEmpty(userBillList)){
            return userBillList;
        }
        List<String> orderIdList = userBillList.stream().map(UserBill::getLinkId).distinct().collect(Collectors.toList());
        List<StoreOrder> storeOrderList = storeOrderService.list(Wrappers.<StoreOrder>lambdaQuery().in(StoreOrder::getId, orderIdList).select(StoreOrder::getId, StoreOrder::getOrderId));
        Map<String, String> orderMap = storeOrderList.stream().collect(Collectors.toMap(e->e.getId().toString(), StoreOrder::getOrderId));
        userBillList.forEach(e -> {
            e.setOrderNo(orderMap.get(e.getLinkId()));
            e.setTitle(getTitle(e.getType()));
        });
        return userBillList;
    }

    @Override
    public PageInfo<UserSpreadOrderItemChildResponse> getV3SpreadOrder(PageParamRequest pageParamRequest) {
        Page<UserCommission> userCommissionPage = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        Integer userId = userService.getUserIdException();
        LambdaQueryWrapper<UserCommission> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserCommission::getUid,userId);
        lambdaQueryWrapper.eq(UserCommission::getType, CommissionTypeEnum.YJ_佣金.getCode());
//        lambdaQueryWrapper.isNotNull(UserCommission::getTotalAmount);
        lambdaQueryWrapper.groupBy(UserCommission::getOrderId);
        lambdaQueryWrapper.select(UserCommission::getOrderId, UserCommission::getFreezeAmount);
        lambdaQueryWrapper.orderByDesc(UserCommission::getCreateTime);
        List<UserCommission> queryList = userCommissionService.list(lambdaQueryWrapper);
        List<UserCommission> commissionList = queryList.stream().filter(e -> e.getFreezeAmount() == null || e.getFreezeAmount().compareTo(BigDecimal.ZERO) != 0).collect(Collectors.toList());

        if(CollectionUtils.isEmpty(commissionList)){
            return CommonPage.copyPageInfo(userCommissionPage, new ArrayList<>());
        }
        List<StoreOrderInfo> storeOrderInfoList = storeOrderInfoService.list(Wrappers.<StoreOrderInfo>lambdaQuery().in(StoreOrderInfo::getChildOrderNumber, commissionList.stream().map(UserCommission::getOrderId).collect(Collectors.toList())));
        List<StoreOrder> storeOrderList = storeOrderService.list(Wrappers.<StoreOrder>lambdaQuery().in(StoreOrder::getId, storeOrderInfoList.stream().map(StoreOrderInfo::getOrderId).collect(Collectors.toList())));
        Map<Integer, StoreOrder> orderMap = storeOrderList.stream().collect(Collectors.toMap(StoreOrder::getId, e -> e));
        List<User> userList = userService.list(Wrappers.<User>lambdaQuery().in(User::getUid, storeOrderList.stream().map(StoreOrder::getUid).collect(Collectors.toList())));
        Map<Integer, User> userMap = userList.stream().collect(Collectors.toMap(User::getUid, e -> e));
        List<UserSpreadOrderItemChildResponse> responses = new ArrayList<>();
        storeOrderInfoList.forEach(info->{
            UserSpreadOrderItemChildResponse response = new UserSpreadOrderItemChildResponse();
            response.setOrderId(info.getChildOrderNumber());
            StoreOrder storeOrder = orderMap.get(info.getOrderId());
            User user = userMap.get(storeOrder.getUid());
            response.setTime(info.getCreateTime());
            response.setAvatar(user.getAvatar());
            response.setNickname(user.getNickname());
            responses.add(response);
        });
        return CommonPage.copyPageInfo(userCommissionPage, responses);
    }

    @Override
    public Boolean removeUser(Integer uid) {
        //删除用户
        userService.removeById(uid);
        //删除用户优惠券
        storeCouponUserService.remove(Wrappers.<StoreCouponUser>lambdaQuery()
                .eq(StoreCouponUser::getUid, uid));
        userTokenService.remove(Wrappers.<UserToken>lambdaQuery()
                .eq(UserToken::getUid, uid));
        return true;
    }

    private String getTitle(String type) {
        String title = "";
        switch (type){
            case Constants.USER_BILL_TYPE_SYSTEM_ADD://后台操作
                title = "商家操作";
                break;
            case Constants.USER_BILL_TYPE_PAY_ORDER://订单支付
                title = "交易支付";
                break;
            case Constants.USER_BILL_TYPE_BROKERAGE://活动领取
                title = "活动领取";
                break;
            case Constants.ORDER_STATUS_BARGAIN://用户已收获
                title = "交易完成";
                break;
            case Constants.USER_BILL_TYPE_DEDUCTION://积分抵扣
                title = "购买商品";
                break;
            case Constants.USER_BILL_TYPE_SIGN://签到
                title = "签到获得";
                break;
            case Constants.USER_BILL_TYPE_GIVE://取消订单返还
                title = "交易取消";
                break;
            case Constants.USER_BILL_TYPE_PAY_PRODUCT_INTEGRAL_BACK://商品退款返还
                title = "交易退款";
                break;
            case Constants.USER_BILL_TYPE_EXCHANGE:
                title = "积分商城兑换商品";
            default:
                break;
        }
        return title;
    }

    /**
     * 授权获取用户手机号 - 解密用户手机号
     *
     * @param request
     */
    private String decryptUserPhone(AuthorizePhoneRequest request) {
        byte[] dataByte = Base64.decodeBase64(request.getEncryptedData());
        // 加密秘钥
        byte[] keyByte = Base64.decodeBase64(request.getSessionKey());
        // 偏移量
        byte[] ivByte = Base64.decodeBase64(request.getIv());
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, StandardCharsets.UTF_8);
                return JSONObject.parseObject(result).toJSONString();
            }
        } catch (Exception e) {
            log.error("授权获取用户手机号 - 解密用户手机号异常: "+e);
            return null;
        }
        return null;
    }

    /**
     * 授权获取用户手机号 - 解析数据
     *
     * @param result
     * @return
     */
    private AuthorizePhoneVo dealAuthorizePhoneResult(String result) {

        AuthorizePhoneVo authorizePhone = new AuthorizePhoneVo();
        try {
            JSONObject resultJson = JSONObject.parseObject(result);
            if (null != resultJson) {
                if (null != resultJson) {
                    authorizePhone = JSONObject.parseObject(resultJson.toString(), AuthorizePhoneVo.class);
                }
            }

            //解密成功
            if (ObjectUtil.isNotEmpty(authorizePhone)) {
                String phoneNumber = authorizePhone.getPhoneNumber();
                String purePhoneNumber = authorizePhone.getPurePhoneNumber();
                if (StringUtils.isBlank(phoneNumber)) {
                    authorizePhone.setPhoneNumber(purePhoneNumber);
                }
                return authorizePhone;
            }
        }catch (Exception e){
            log.error("授权获取用户手机号 - 解析数据异常: "+e);
        }

        return null;
    }

}
